using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Web.Hosting;
using System.Web;
using System.IO;
using System.ServiceModel.Syndication;
//using VppSample;
using NCMIS.ObjectModel;
using NCMIS.ObjectModel.MetaData;
using NCMIS.ObjectModel.Rest;
using NCMIS.Client;
using NCMIS.ServiceModel.Syndication;
using System.Text.RegularExpressions;

namespace EPiServer.Web.Hosting
{
    public class VirtualPathCmisProvider : VirtualPathUnifiedProvider
    {
        protected CmisDirectory root;
        protected CmisWebRequest cmisWebReq;

        /// <summary>
        /// VPP constructor. 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="configParameters"></param>
        public VirtualPathCmisProvider(string name, NameValueCollection configParameters) : base(name, configParameters)
        {
            base.ValidateAndSetupConfigParams();

             // Create the root of our sample impl. virtual path filesystem.
            root = new CmisDirectory(this, VirtualPathUtility.AppendTrailingSlash(VirtualPathUtility.ToAbsolute(ConfigurationParameters["virtualPath"])));
        
            // Read credentials and service doc uri from episerver.config
            string userName = ConfigurationParameters["userName"];
            string password = ConfigurationParameters["password"];
            string serviceDocURI = ConfigurationParameters["serviceDocumentUri"];

            // Create a (CMIS) web request
            cmisWebReq = new CmisWebRequest(userName, password, new Uri(serviceDocURI));

            // Obtain the service document and use it to get the root folder collection
            ServiceDocument serviceDoc = cmisWebReq.GetServiceDocument();
            ResourceCollectionInfo rootFldrCollection = serviceDoc.GetCollection(ServiceDocumentCollection.RootFolder);

            // Access the root folder feed using its URI
            Uri rootFldrURI = rootFldrCollection.Link;
            SyndicationFeed rootFldrFeed = cmisWebReq.GetSyndicationFeed(rootFldrURI.AbsoluteUri);

            // Get the links to the root folder and root folder children feeds
            SyndicationLink rootFldrLink = CmisSyndicationFeed.GetLink(rootFldrFeed, CmisLinkRel.Via);
            SyndicationLink rootFldrChildrenLink = CmisSyndicationFeed.GetLink(rootFldrFeed, CmisLinkRel.Self);
            root.SelfURI = rootFldrLink.Uri;
            root.ChildrenURI = rootFldrChildrenLink.Uri;
        }

        /// <summary>
        /// Check if this virtual filesystems has this file based upon virtual file.
        /// Otherwise pass to the next provider.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        public override bool FileExists(string virtualPath)
        {
            if (virtualPath.StartsWith(root.VirtualPath, StringComparison.InvariantCultureIgnoreCase))
            {
                return (FindFile(virtualPath) != null);
            }

            return Previous.FileExists(virtualPath);
        }


        /// <summary>
        /// Check if this virtual filesystems has this directory based upon virtual file.
        /// Othervise pass to next provider.
        /// </summary>
        /// <param name="virtualDir"></param>
        /// <returns></returns>
        public override bool DirectoryExists(string virtualDir)
        {
            if (virtualDir.StartsWith(root.VirtualPath, StringComparison.InvariantCultureIgnoreCase))
            {
                return (FindDirectory(virtualDir) != null);
            }
            return Previous.DirectoryExists(virtualDir);
        }

        /// <summary>
        /// Gets the file from the sample file system.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        public override VirtualFile GetFile(string virtualPath)
        {
            if (virtualPath.StartsWith(root.VirtualPath, StringComparison.InvariantCultureIgnoreCase))
            {
                return FindFile(virtualPath);
            }
            return Previous.GetFile(virtualPath);
        }

        /// <summary>
        /// Gets the directory from the sample file system.
        /// </summary>
        /// <param name="virtualDir"></param>
        /// <returns></returns>
        public override VirtualDirectory GetDirectory(string virtualDir)
        {
            // Create a regular expression to check virtual path patterns
            // =================================================
            // TO DO: Write a regular expression that only accepts paths in the form of "/.../",
            // i.e. not "~/.../". We want it to work exactly as now, but for all paths, not just
            // those that start with /WTest.
            //Match match = Regex.Match(virtualDir, "(?=^~.+)(?=/.+)", RegexOptions.None);  // Tried using look-ahead, didn't work
            // =================================================

            if (virtualDir.StartsWith(root.VirtualPath, StringComparison.InvariantCultureIgnoreCase))
            {
                CmisDirectory tempDir = FindDirectory(virtualDir);
                return tempDir;
            }
            else if(virtualDir.StartsWith("/WTest"))  // Keep this for now, until a solution is found
            //else if (match.Sucess)    // Implement this instead once regex is complete
            {
                CmisDirectory tempDir = FindDirectory(virtualDir);
                return tempDir;
            }
            return Previous.GetDirectory(virtualDir);
       }

        /// <summary>
        /// Splits the virtual path and removes empty entries.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        protected virtual IList<string> SplitVirtualPath(string virtualPath)
        {
            return SplitVirtualPath(virtualPath, false);    
        }

        /// <summary>
        /// Splits the virtual path and removes empty entries. Option is to remove the
        /// path from the root directory.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <param name="removeRoot"></param>
        /// <returns></returns>
        protected virtual IList<string> SplitVirtualPath(string virtualPath, bool removeRoot)
        {
            if(removeRoot)
            {
                virtualPath = virtualPath.Remove(0, root.VirtualPath.Length -1);
            }
            return new List<string>(virtualPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries));
        }

        /// <summary>
        /// Checks if the Virtual Path is the same as for the root directory.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        protected virtual bool IsVirtualPathToRootDirectory(string virtualPath)
        {
            return (String.Compare(virtualPath, root.VirtualPath, true) == 0);
        }

        /// <summary>
        /// Attempts to find the CmisFile from the virtual path passed to the provider.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        protected virtual CmisFile FindFile(string virtualPath)
        {
            string fileName = VirtualPathUtility.GetFileName(virtualPath);

            CmisDirectory fileParentDirectory = FindDirectory(VirtualPathUtility.GetDirectory(virtualPath));
            if (fileParentDirectory == null)
            {
                return null;
            }
            return fileParentDirectory.GetFile(fileName);
        }
        
        /// <summary>
        /// Attempts to find the CmisDirectory from the virtual path passed to the provider.
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <returns></returns>
        protected virtual CmisDirectory FindDirectory(string virtualPath)
        {
            CmisDirectory currentDirectory = root;
            IList<string> dirPath;

            // Only split the virtual path if it contains the root path
            if (virtualPath.Contains(root.VirtualPath))
            {
                dirPath = SplitVirtualPath(virtualPath, true);
            }
            else
            {
                dirPath = SplitVirtualPath(virtualPath, false);
            }

            // Attempt to find the directory
            foreach (string subDir in dirPath)
            {               
                if((currentDirectory = currentDirectory.GetDirectory(subDir)) == null)
                {
                    return null;
                }
            }

            return currentDirectory;
        }
    }
}
